1use crate::AviUtl2Info;
2use pastey::paste;
3use std::num::NonZeroIsize;
4
5pub struct HostAppHandle<'a> {
12 internal: *mut aviutl2_sys::plugin2::HOST_APP_TABLE,
13 global_leak_manager: &'a mut crate::common::LeakManager,
14 is_register_plugin_done: std::sync::Arc<std::sync::atomic::AtomicBool>,
15 plugin_registry: &'a mut crate::generic::PluginRegistry,
16 is_edit_handle_available: std::sync::Arc<std::sync::atomic::AtomicBool>,
17}
18
19pub struct SubPlugin<T> {
21 plugin: std::marker::PhantomData<T>,
22 internal: std::sync::Arc<InternalReferenceHandle>,
23}
24struct InternalReferenceHandle {
25 uninitialize_fn: fn(),
26}
27impl Drop for InternalReferenceHandle {
28 fn drop(&mut self) {
29 (self.uninitialize_fn)();
30 }
31}
32
33impl<'plugin> HostAppHandle<'plugin> {
34 pub(crate) unsafe fn new(
35 internal: *mut aviutl2_sys::plugin2::HOST_APP_TABLE,
36 global_leak_manager: &'plugin mut crate::common::LeakManager,
37 is_register_plugin_done: std::sync::Arc<std::sync::atomic::AtomicBool>,
38 plugin_registry: &'plugin mut crate::generic::PluginRegistry,
39 is_edit_handle_available: std::sync::Arc<std::sync::atomic::AtomicBool>,
40 ) -> Self {
41 Self {
42 internal,
43 global_leak_manager,
44 is_register_plugin_done,
45 plugin_registry,
46 is_edit_handle_available,
47 }
48 }
49
50 fn assert_not_killed(&self) {
51 if self
52 .is_register_plugin_done
53 .load(std::sync::atomic::Ordering::SeqCst)
54 {
55 panic!("This HostAppHandle is no longer valid.");
56 }
57 }
58
59 pub fn create_edit_handle(&mut self) -> crate::generic::EditHandle {
61 self.assert_not_killed();
62 let raw_handle = unsafe { ((*self.internal).create_edit_handle)() };
63 unsafe {
64 crate::generic::EditHandle::new(raw_handle, self.is_edit_handle_available.clone())
65 }
66 }
67
68 pub fn register_import_menu<F>(&mut self, name: &str, callback: F)
74 where
75 F: Fn() + 'static + Send + Sync,
76 {
77 self.register_menu_internal(name, callback, unsafe {
78 (*self.internal).register_import_menu_param
79 });
80 }
81
82 pub fn register_export_menu<F>(&mut self, name: &str, callback: F)
88 where
89 F: Fn() + 'static + Send + Sync,
90 {
91 self.register_menu_internal(name, callback, unsafe {
92 (*self.internal).register_export_menu_param
93 });
94 }
95
96 pub fn register_layer_menu<F>(&mut self, name: &str, callback: F)
104 where
105 F: Fn() + 'static + Send + Sync,
106 {
107 self.register_menu_internal(name, callback, unsafe {
108 (*self.internal).register_layer_menu_param
109 });
110 }
111
112 pub fn register_object_menu<F>(&mut self, name: &str, callback: F)
120 where
121 F: Fn() + 'static + Send + Sync,
122 {
123 self.register_menu_internal(name, callback, unsafe {
124 (*self.internal).register_object_menu_param
125 });
126 }
127
128 pub fn register_edit_menu<F>(&mut self, name: &str, callback: F)
135 where
136 F: Fn() + 'static + Send + Sync,
137 {
138 self.register_menu_internal(name, callback, unsafe {
139 (*self.internal).register_edit_menu_param
140 });
141 }
142
143 pub fn register_config_menu(
150 &mut self,
151 name: &str,
152 callback: extern "C" fn(aviutl2_sys::plugin2::HWND, aviutl2_sys::plugin2::HINSTANCE),
153 ) {
154 self.assert_not_killed();
155 unsafe {
156 ((*self.internal).register_config_menu)(
157 self.global_leak_manager.leak_as_wide_string(name),
158 callback,
159 )
160 };
161 }
162
163 pub fn register_object_item_menu<F>(&mut self, name: &str, callback: F)
177 where
178 F: Fn(crate::generic::ObjectHandle, &str, usize, &str) + 'static + Send + Sync,
179 {
180 self.assert_not_killed();
181 let trampoline_param: Box<F> = Box::new(callback);
182 let trampoline_param_ptr = Box::into_raw(trampoline_param);
183 let name_wide = self.global_leak_manager.leak_as_wide_string(name);
184 unsafe {
185 ((*self.internal).register_object_item_menu_param)(
186 name_wide,
187 false,
188 trampoline_param_ptr as *mut std::ffi::c_void,
189 trampoline::<F>,
190 );
191 }
192
193 unsafe extern "C" fn trampoline<F>(
194 param: *mut std::ffi::c_void,
195 object_handle: aviutl2_sys::plugin2::OBJECT_HANDLE,
196 name_and_index: aviutl2_sys::common::LPCWSTR,
197 item_name: aviutl2_sys::common::LPCWSTR,
198 ) where
199 F: Fn(crate::generic::ObjectHandle, &str, usize, &str) + 'static + Send + Sync,
200 {
201 let callback = unsafe { &mut *(param as *mut F) };
202 let object_handle = crate::generic::ObjectHandle::from(object_handle);
203 let name_and_index_str = unsafe { crate::common::load_wide_string(name_and_index) };
204 let (name_str, index) = parse_name_and_index(&name_and_index_str);
205 let item_name_str = unsafe { crate::common::load_wide_string(item_name) };
206 if let Err(panic_info) =
207 crate::utils::catch_unwind_with_panic_info(std::panic::AssertUnwindSafe(|| {
208 callback(object_handle, name_str, index, &item_name_str);
209 }))
210 {
211 tracing::error!(
212 "Panic occurred in object item menu callback: {}",
213 panic_info
214 );
215 let _ = crate::logger::write_error_log(&panic_info);
216 }
217 }
218 }
219
220 pub fn register_object_item_and_effect_menu<F>(&mut self, name: &str, callback: F)
234 where
235 F: Fn(crate::generic::ObjectHandle, &str, usize, Option<&str>) + 'static + Send + Sync,
236 {
237 self.assert_not_killed();
238 let trampoline_param: Box<F> = Box::new(callback);
239 let trampoline_param_ptr = Box::into_raw(trampoline_param);
240 let name_wide = self.global_leak_manager.leak_as_wide_string(name);
241 unsafe {
242 ((*self.internal).register_object_item_menu_param)(
243 name_wide,
244 true,
245 trampoline_param_ptr as *mut std::ffi::c_void,
246 trampoline::<F>,
247 );
248 }
249
250 unsafe extern "C" fn trampoline<F>(
251 param: *mut std::ffi::c_void,
252 object_handle: aviutl2_sys::plugin2::OBJECT_HANDLE,
253 effect_name_and_index: aviutl2_sys::common::LPCWSTR,
254 item_name: aviutl2_sys::common::LPCWSTR,
255 ) where
256 F: Fn(crate::generic::ObjectHandle, &str, usize, Option<&str>) + 'static + Send + Sync,
257 {
258 let callback = unsafe { &mut *(param as *mut F) };
259 let object_handle = crate::generic::ObjectHandle::from(object_handle);
260 let effect_name_and_index =
261 unsafe { crate::common::load_wide_string(effect_name_and_index) };
262 let item_name = (!item_name.is_null())
263 .then(|| unsafe { crate::common::load_wide_string(item_name) });
264
265 let (effect_name_str, index) = parse_name_and_index(&effect_name_and_index);
266 let item_name_option = item_name.as_deref();
267 if let Err(panic_info) =
268 crate::utils::catch_unwind_with_panic_info(std::panic::AssertUnwindSafe(|| {
269 callback(object_handle, effect_name_str, index, item_name_option);
270 }))
271 {
272 tracing::error!(
273 "Panic occurred in object item menu with effect callback: {}",
274 panic_info
275 );
276 let _ = crate::logger::write_error_log(&panic_info);
277 }
278 }
279 }
280
281 pub fn register_file_drop_handler<F>(
289 &mut self,
290 name: &str,
291 file_filters: &[crate::common::FileFilter],
292 callback: F,
293 ) where
294 F: Fn(std::path::PathBuf) + 'static + Send + Sync,
295 {
296 self.assert_not_killed();
297 let callback_box = Box::new(callback);
298 let callback_ptr = Box::into_raw(callback_box);
299 let name_wide = self.global_leak_manager.leak_as_wide_string(name);
300 let file_filter_wide = self
301 .global_leak_manager
302 .leak_as_wide_string(&crate::common::format_file_filters(file_filters));
303 unsafe {
304 ((*self.internal).register_file_drop_param_handler)(
305 name_wide,
306 file_filter_wide,
307 callback_ptr as *mut std::ffi::c_void,
308 file_drop_trampoline::<F>,
309 );
310 }
311 }
312
313 pub fn register_window_client<T: raw_window_handle::HasWindowHandle>(
319 &mut self,
320 name: &str,
321 instance: &T,
322 ) -> Result<(), raw_window_handle::HandleError> {
323 self.assert_not_killed();
324 let raw_handle = instance.window_handle()?;
325 let hwnd = match raw_handle.as_raw() {
326 raw_window_handle::RawWindowHandle::Win32(handle) => handle.hwnd,
327 _ => panic!("Only Win32WindowHandle is supported"),
328 };
329 unsafe {
330 ((*self.internal).register_window_client)(
331 self.global_leak_manager.leak_as_wide_string(name),
332 hwnd.get() as *mut std::ffi::c_void,
333 );
334 }
335 Ok(())
336 }
337
338 pub fn register_menus<T: GenericPluginMenus>(&mut self) {
344 self.assert_not_killed();
345 T::register_menus(self);
346 }
347
348 pub fn register_project_load_handler<F>(&mut self, callback: F)
356 where
357 F: Fn(&mut crate::generic::ProjectFile) + 'static + Send + Sync,
358 {
359 self.assert_not_killed();
360
361 type CallbackType = Box<dyn Fn(&mut crate::generic::ProjectFile) + Send + Sync>;
362 static CALLBACKS: std::sync::Mutex<Vec<CallbackType>> = std::sync::Mutex::new(Vec::new());
363
364 let callback_box = Box::new(callback);
365 let mut callbacks = CALLBACKS.lock().unwrap();
366 if callbacks.is_empty() {
367 unsafe extern "C" fn trampoline(project_file: *mut aviutl2_sys::plugin2::PROJECT_FILE) {
368 let callbacks = CALLBACKS.lock().unwrap();
369 let mut project_file =
370 unsafe { crate::generic::ProjectFile::from_raw(project_file) };
371 for callback in callbacks.iter() {
372 if let Err(panic_info) = crate::utils::catch_unwind_with_panic_info(
373 std::panic::AssertUnwindSafe(|| {
374 callback(&mut project_file);
375 }),
376 ) {
377 tracing::error!("Panic occurred in project load callback: {}", panic_info);
378 let _ = crate::logger::write_error_log(&panic_info);
379 }
380 }
381 }
382 unsafe {
383 ((*self.internal).register_project_load_handler)(trampoline);
384 }
385 }
386
387 callbacks.push(callback_box);
388 }
389
390 pub fn register_project_save_handler<F>(&mut self, callback: F)
397 where
398 F: Fn(&mut crate::generic::ProjectFile) + 'static + Send + Sync,
399 {
400 self.assert_not_killed();
401
402 type CallbackType = Box<dyn Fn(&mut crate::generic::ProjectFile) + Send + Sync>;
403 static CALLBACKS: std::sync::Mutex<Vec<CallbackType>> = std::sync::Mutex::new(Vec::new());
404
405 let callback_box = Box::new(callback);
406 let mut callbacks = CALLBACKS.lock().unwrap();
407 if callbacks.is_empty() {
408 unsafe extern "C" fn trampoline(project_file: *mut aviutl2_sys::plugin2::PROJECT_FILE) {
409 let callbacks = CALLBACKS.lock().unwrap();
410 let mut project_file =
411 unsafe { crate::generic::ProjectFile::from_raw(project_file) };
412 for callback in callbacks.iter() {
413 if let Err(panic_info) = crate::utils::catch_unwind_with_panic_info(
414 std::panic::AssertUnwindSafe(|| {
415 callback(&mut project_file);
416 }),
417 ) {
418 tracing::error!("Panic occurred in project save callback: {}", panic_info);
419 let _ = crate::logger::write_error_log(&panic_info);
420 }
421 }
422 }
423 unsafe {
424 ((*self.internal).register_project_save_handler)(trampoline);
425 }
426 }
427
428 callbacks.push(callback_box);
429 }
430
431 pub fn register_clear_cache_handler<F>(&mut self, callback: F)
438 where
439 F: Fn(&crate::generic::EditSection) + 'static + Send + Sync,
440 {
441 self.assert_not_killed();
442
443 type CallbackType = Box<dyn Fn(&crate::generic::EditSection) + Send + Sync>;
444 static CALLBACKS: std::sync::Mutex<Vec<CallbackType>> = std::sync::Mutex::new(Vec::new());
445
446 let callback_box = Box::new(callback);
447 let mut callbacks = CALLBACKS.lock().unwrap();
448 if callbacks.is_empty() {
449 unsafe extern "C" fn trampoline(edit_section: *mut aviutl2_sys::plugin2::EDIT_SECTION) {
450 let callbacks = CALLBACKS.lock().unwrap();
451 let edit_section = unsafe { crate::generic::EditSection::from_raw(edit_section) };
452 for callback in callbacks.iter() {
453 if let Err(panic_info) = crate::utils::catch_unwind_with_panic_info(
454 std::panic::AssertUnwindSafe(|| {
455 callback(&edit_section);
456 }),
457 ) {
458 tracing::error!("Panic occurred in clear cache callback: {}", panic_info);
459 let _ = crate::logger::write_error_log(&panic_info);
460 }
461 }
462 }
463 unsafe {
464 ((*self.internal).register_clear_cache_handler)(trampoline);
465 }
466 }
467
468 callbacks.push(callback_box);
469 }
470
471 pub fn register_change_scene_handler<F>(&mut self, callback: F)
483 where
484 F: Fn(&crate::generic::EditSection) + 'static + Send + Sync,
485 {
486 self.assert_not_killed();
487
488 type CallbackType = Box<dyn Fn(&crate::generic::EditSection) + Send + Sync>;
489 static CALLBACKS: std::sync::Mutex<Vec<CallbackType>> = std::sync::Mutex::new(Vec::new());
490
491 let callback_box = Box::new(callback);
492 let mut callbacks = CALLBACKS.lock().unwrap();
493 if callbacks.is_empty() {
494 unsafe extern "C" fn trampoline(edit_section: *mut aviutl2_sys::plugin2::EDIT_SECTION) {
495 let callbacks = CALLBACKS.lock().unwrap();
496 let edit_section = unsafe { crate::generic::EditSection::from_raw(edit_section) };
497 for callback in callbacks.iter() {
498 if let Err(panic_info) = crate::utils::catch_unwind_with_panic_info(
499 std::panic::AssertUnwindSafe(|| {
500 callback(&edit_section);
501 }),
502 ) {
503 tracing::error!("Panic occurred in change scene callback: {}", panic_info);
504 let _ = crate::logger::write_error_log(&panic_info);
505 }
506 }
507 }
508 unsafe {
509 ((*self.internal).register_change_scene_handler)(trampoline);
510 }
511 }
512
513 callbacks.push(callback_box);
514 }
515
516 pub fn register_event_listener<F>(&mut self, event_type: EventType, callback: F)
523 where
524 F: Fn() + 'static + Send + Sync,
525 {
526 self.assert_not_killed();
527 let callback_box = Box::new(callback);
528 let callback_ptr = Box::into_raw(callback_box);
529 unsafe {
530 ((*self.internal).register_event_listener)(
531 event_type.into(),
532 callback_ptr as *mut std::ffi::c_void,
533 event_listener_trampoline::<F>,
534 );
535 }
536 }
537
538 fn register_menu_internal<F>(
539 &mut self,
540 name: &str,
541 callback: F,
542 register_fn: unsafe extern "C" fn(
543 aviutl2_sys::common::LPCWSTR,
544 *mut std::ffi::c_void,
545 unsafe extern "C" fn(*mut std::ffi::c_void),
546 ),
547 ) where
548 F: Fn() + 'static + Send + Sync,
549 {
550 self.assert_not_killed();
551 let trampoline_param: Box<MenuTrampolineParam<F>> = Box::new(callback);
552 let trampoline_param_ptr = Box::into_raw(trampoline_param);
553 unsafe {
554 register_fn(
555 self.global_leak_manager.leak_as_wide_string(name),
556 trampoline_param_ptr as *mut std::ffi::c_void,
557 menu_trampoline::<F>,
558 );
559 }
560 }
561}
562
563#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
565pub enum EventType {
566 UpdateObject,
568 ChangeEditFrame,
570 ChangeEditScene,
572 ChangeFocusObject,
574}
575
576impl From<EventType> for aviutl2_sys::plugin2::EVENT_TYPE {
577 fn from(value: EventType) -> Self {
578 match value {
579 EventType::UpdateObject => aviutl2_sys::plugin2::EVENT_TYPE::UPDATE_OBJECT,
580 EventType::ChangeEditFrame => aviutl2_sys::plugin2::EVENT_TYPE::CHANGE_EDIT_FRAME,
581 EventType::ChangeEditScene => aviutl2_sys::plugin2::EVENT_TYPE::CHANGE_EDIT_SCENE,
582 EventType::ChangeFocusObject => aviutl2_sys::plugin2::EVENT_TYPE::CHANGE_FOCUS_OBJECT,
583 }
584 }
585}
586
587fn parse_name_and_index(name_and_index: &str) -> (&str, usize) {
588 let Some(pos) = name_and_index.rfind(':') else {
589 return (name_and_index, 0);
590 };
591 let index_str = &name_and_index[pos + 1..];
592 if let Ok(index) = index_str.parse::<usize>() {
593 let name = &name_and_index[..pos];
594 (name, index)
595 } else {
596 (name_and_index, 0)
597 }
598}
599
600type MenuTrampolineParam<F> = F;
601
602unsafe extern "C" fn menu_trampoline<F>(param: *mut std::ffi::c_void)
603where
604 F: Fn() + 'static + Send + Sync,
605{
606 let callback = unsafe { &mut *(param as *mut MenuTrampolineParam<F>) };
607 if let Err(panic_info) =
608 crate::utils::catch_unwind_with_panic_info(std::panic::AssertUnwindSafe(callback))
609 {
610 tracing::error!("Panic occurred in menu callback: {}", panic_info);
611 let _ = crate::logger::write_error_log(&panic_info);
612 }
613}
614
615unsafe extern "C" fn file_drop_trampoline<F>(
616 param: *mut std::ffi::c_void,
617 file_path: aviutl2_sys::common::LPCWSTR,
618) where
619 F: Fn(std::path::PathBuf) + 'static + Send + Sync,
620{
621 let callback = unsafe { &mut *(param as *mut F) };
622 let path_str = unsafe { crate::common::load_wide_string(file_path) };
623 let path = std::path::PathBuf::from(path_str);
624 if let Err(panic_info) =
625 crate::utils::catch_unwind_with_panic_info(std::panic::AssertUnwindSafe(|| {
626 callback(path);
627 }))
628 {
629 tracing::error!("Panic occurred in file drop callback: {}", panic_info);
630 let _ = crate::logger::write_error_log(&panic_info);
631 }
632}
633
634unsafe extern "C" fn event_listener_trampoline<F>(param: *mut std::ffi::c_void)
635where
636 F: Fn() + 'static + Send + Sync,
637{
638 let callback = unsafe { &mut *(param as *mut F) };
639 if let Err(panic_info) =
640 crate::utils::catch_unwind_with_panic_info(std::panic::AssertUnwindSafe(callback))
641 {
642 tracing::error!("Panic occurred in event listener callback: {}", panic_info);
643 let _ = crate::logger::write_error_log(&panic_info);
644 }
645}
646
647pub trait GenericPluginMenus {
656 fn register_menus(host: &mut crate::generic::HostAppHandle);
657}
658
659#[doc(inline)]
660pub use aviutl2_macros::generic_menus as menus;
661
662#[derive(Default)]
663pub(crate) struct PluginRegistry {
664 #[cfg(feature = "input")]
665 input_plugins: Vec<std::sync::Arc<InternalReferenceHandle>>,
666 #[cfg(feature = "output")]
667 output_plugins: Vec<std::sync::Arc<InternalReferenceHandle>>,
668 #[cfg(feature = "filter")]
669 filter_plugins: Vec<std::sync::Arc<InternalReferenceHandle>>,
670 #[cfg(feature = "module")]
671 script_modules: Vec<std::sync::Arc<InternalReferenceHandle>>,
672}
673impl PluginRegistry {
674 pub(crate) fn new() -> Self {
675 Self::default()
676 }
677}
678
679macro_rules! impl_plugin_registry {
680 (
681 $description:literal,
682 $feature:literal,
683 $module:ident,
684 $name:ident,
685 $register_method:ident,
686 $PluginTrait:path,
687 $SingletonTrait:path,
688 $TableType:ty
689 ) => {
690 paste! {
691 impl<T> SubPlugin<T> {
692 #[cfg(feature = $feature)]
693 #[doc = concat!($description, "の新しいインスタンスを作成します。")]
694 pub fn [<new_ $name>](info: &AviUtl2Info) -> crate::AnyResult<Self>
695 where
696 T: $PluginTrait + $SingletonTrait + 'static
697 {
698 crate::$module::__bridge::initialize_plugin::<T>(info.version.into())?;
699 let internal = std::sync::Arc::new(InternalReferenceHandle {
700 uninitialize_fn: || {
701 unsafe {
702 crate::$module::__bridge::uninitialize_plugin::<T>();
703 }
704 },
705 });
706 Ok(Self {
707 plugin: std::marker::PhantomData,
708 internal,
709 })
710 }
711 }
712 #[cfg(feature = $feature)]
713 impl<'a> HostAppHandle<'a> {
714 #[doc = concat!($description, "を登録します。")]
715 pub fn [<register_ $name>]<T: $PluginTrait + $SingletonTrait + 'static>(
716 &mut self,
717 handle: &SubPlugin<T>,
718 ) {
719 self.assert_not_killed();
720 unsafe { ((*self.internal).$register_method)(crate::$module::__bridge::create_table_unwind::<T>()) };
721 self.plugin_registry
722 .[<$name s>]
723 .push(std::sync::Arc::clone(&handle.internal));
724 }
725 #[doc = concat!("unwindなしで", $description, "を登録します。")]
726 pub fn [<register_ $name _nounwind>]<T: $PluginTrait + $SingletonTrait + 'static>(
727 &mut self,
728 handle: &SubPlugin<T>,
729 ) {
730 self.assert_not_killed();
731 unsafe { ((*self.internal).$register_method)(crate::$module::__bridge::create_table::<T>()) };
732 self.plugin_registry
733 .[<$name s>]
734 .push(std::sync::Arc::clone(&handle.internal));
735 }
736 }
737 }
738 };
739}
740
741impl_plugin_registry!(
742 "入力プラグイン",
743 "input",
744 input,
745 input_plugin,
746 register_input_plugin,
747 crate::input::InputPlugin,
748 crate::input::__bridge::InputSingleton,
749 aviutl2_sys::input2::INPUT_PLUGIN_TABLE
750);
751impl_plugin_registry!(
752 "出力プラグイン",
753 "output",
754 output,
755 output_plugin,
756 register_output_plugin,
757 crate::output::OutputPlugin,
758 crate::output::__bridge::OutputSingleton,
759 aviutl2_sys::output2::OUTPUT_PLUGIN_TABLE
760);
761impl_plugin_registry!(
762 "フィルタープラグイン",
763 "filter",
764 filter,
765 filter_plugin,
766 register_filter_plugin,
767 crate::filter::FilterPlugin,
768 crate::filter::__bridge::FilterSingleton,
769 aviutl2_sys::filter2::FILTER_PLUGIN_TABLE
770);
771#[cfg(feature = "module")]
772impl<T> SubPlugin<T> {
773 pub fn new_script_module(info: &AviUtl2Info) -> crate::AnyResult<Self>
775 where
776 T: crate::module::ScriptModule + crate::module::__bridge::ScriptModuleSingleton + 'static,
777 {
778 crate::module::__bridge::initialize_plugin::<T>(info.version.into())?;
779 let internal = std::sync::Arc::new(InternalReferenceHandle {
780 uninitialize_fn: || unsafe {
781 crate::module::__bridge::uninitialize_plugin::<T>();
782 },
783 });
784 Ok(Self {
785 plugin: std::marker::PhantomData,
786 internal,
787 })
788 }
789}
790
791#[cfg(feature = "module")]
792impl<'a> HostAppHandle<'a> {
793 pub fn register_script_module<
799 T: crate::module::ScriptModule + crate::module::__bridge::ScriptModuleSingleton + 'static,
800 >(
801 &mut self,
802 name: Option<&str>,
803 handle: &SubPlugin<T>,
804 ) {
805 self.assert_not_killed();
806 unsafe {
807 if let Some(name_str) = name {
808 ((*self.internal).register_script_module_name)(
809 crate::module::__bridge::create_table_unwind::<T>(),
810 self.global_leak_manager.leak_as_wide_string(name_str),
811 )
812 } else {
813 ((*self.internal).register_script_module)(
814 crate::module::__bridge::create_table_unwind::<T>(),
815 )
816 }
817 };
818 self.plugin_registry
819 .script_modules
820 .push(std::sync::Arc::clone(&handle.internal));
821 }
822
823 pub fn register_script_module_nounwind<
829 T: crate::module::ScriptModule + crate::module::__bridge::ScriptModuleSingleton + 'static,
830 >(
831 &mut self,
832 name: Option<&str>,
833 handle: &SubPlugin<T>,
834 ) {
835 self.assert_not_killed();
836 unsafe {
837 if let Some(name_str) = name {
838 ((*self.internal).register_script_module_name)(
839 crate::module::__bridge::create_table::<T>(),
840 self.global_leak_manager.leak_as_wide_string(name_str),
841 )
842 } else {
843 ((*self.internal).register_script_module)(
844 crate::module::__bridge::create_table::<T>(),
845 );
846 }
847 };
848 self.plugin_registry
849 .script_modules
850 .push(std::sync::Arc::clone(&handle.internal));
851 }
852}
853
854#[doc(hidden)]
855pub unsafe fn __internal_rwh_from_raw(
856 hwnd: aviutl2_sys::plugin2::HWND,
857 hinstance: aviutl2_sys::plugin2::HINSTANCE,
858) -> raw_window_handle::Win32WindowHandle {
859 let mut handle =
860 raw_window_handle::Win32WindowHandle::new(NonZeroIsize::new(hwnd as isize).unwrap());
861 handle.hinstance = Some(NonZeroIsize::new(hinstance as isize).unwrap());
862 handle
863}